#include "StdAfx.h"
#include "MasterClass.h"


MasterClass::MasterClass(void)
{
	 g = new graph();
}
MasterClass::~MasterClass(void)
{
}

int MasterClass::ProfesorCantidad()
{
	return VecProfesor.size();
}
TProfesor MasterClass::ProfesorObtener(int pos)
{
	TProfesor obj;
	if (pos < ProfesorCantidad())
	{
		return VecProfesor[pos];
	}
	else
	{
		return obj;
	}
}
bool MasterClass::ProfesorExiste(TProfesor objProfesor)
{
	for (int i=0 ; i<VecProfesor.size(); i++)
	{
		if (strcmp(VecProfesor[i].nombre,objProfesor.nombre)==0 && strcmp(VecProfesor[i].apellido,objProfesor.apellido)==0   )
		{
			return true;
		}
	}
	return false;
}
bool MasterClass::ProfesorAgregar(TProfesor objProfesor)
{
	if (!ProfesorExiste(objProfesor))
	{
		VecProfesor.push_back(objProfesor);
		return true;
	}
	else
		return false;
}
int MasterClass::AulaCantidad()
{
	return VecAulas.size();	
}
TAula MasterClass::AulaObtener(int pos)
{
   TAula obj;
   if(pos < AulaCantidad())
   {
		return VecAulas[pos];
   }
   else
	   return obj;
}
bool MasterClass::AulaExiste(TAula objAula)
{
	for (int i=0 ; i<VecAulas.size() ;i++)
	{
		if (strcmp(VecAulas[i].nombre,objAula.nombre)==0)
		{
			return true;
		}
	}
	return false;
}
bool MasterClass::AulaAgregar(TAula objAula)
{
	if (!AulaExiste(objAula))
	{
		VecAulas.push_back(objAula);
		return true;
	} 
	else
	{
		return false;
	}
}
TCurso MasterClass::CursoObtener(int pos)
{
	 return VecCurso[pos];
}
void MasterClass::TCursoGenerar()
{	
	VecCurso.clear();
	int TCursoID = 1;
	for (int i=0 ;i<VecProfesor.size() ; i++) // i para los profes
	{
		for (int k=0 ; k<VecProfesor[i].asignaturas.size() ;k++)   // k asignaturas del profe
		{
			int n = (VecProfesor[i].asignaturas[k].CantidadHoras)/2;
			for (int j=1 ; j<=n ; j++) // j determina el numero de sesiones de la Asignatura
			{
				// recorremos la matriz de horario del profesor
				for (int dia=0 ; dia<7 ; dia++)
				{
					for(int hora=0 ; hora<15 ; hora++)
					{
						if (VecProfesor[i].horario[dia][hora]==0 && VecProfesor[i].horario[dia][hora+1]==0 )
						{
							TCurso objTCurso;
							objTCurso.asignatura = VecProfesor[i].asignaturas[k];
							objTCurso.dia=dia;
							objTCurso.horaInicio=hora;
							objTCurso.profesor=VecProfesor[i];
							objTCurso.sesion=j;
							objTCurso.TCursoID = TCursoID;
							TCursoID++;
							VecCurso.push_back(objTCurso);
						}
					}
				}
			}
		}
	}
}
void MasterClass::TAulaAsignarID()
{
	int TAulaID = VecCurso.size();
	for (int i=0 ; i<VecAulas.size() ; i++)
	{
		TAulaID++;
		VecAulas[i].TAulaID=TAulaID;
	}
}
void MasterClass::AsociarNodos()
{
	for (int i=0 ; i<VecCurso.size() ; i++)
		for (int k=0 ; k<VecAulas.size(); k++)
			insert_edge(VecCurso[i].TCursoID,VecAulas[k].TAulaID,2,false);

	for (int i=0 ; i<VecCurso.size() ; i++)
		insert_edge(0,VecCurso[i].TCursoID,2,false);
	for (int i=0 ; i<VecAulas.size() ;i++)
		insert_edge(VecAulas[i].TAulaID,n,VecAulas[i].HorasDisponibles,false);
	
}
void MasterClass::GenerarGrafo()
{
	TCursoGenerar();
	TAulaAsignarID();
	initialize_graph();
	AsociarNodos();
	this->s=0;
	this->t=n;

}
void MasterClass::Solucion()
{
	GenerarGrafo();
	edmondsKarps();
}
bool MasterClass::Convalidaciones(int inicio,int destino)
{
	if (inicio==0)
	{
		return true;
	}
	else
	{
		int pos = VecCurso.size();
		if (inicio <= pos)
		{
			//-- Validar Profesor disponible
			//-- Validar Aula disponible
			//-- Validar que no se cruce la seccion
			//-- Validad que no se repita la session
			if(ValidarHorarioProfesor(inicio) && ValidarHorarioAula(inicio,destino) && ValidarCruceSeccion(inicio) && ValidarSession(inicio) )
			{
				return true;
			}
			else
				return false;
		}
		else
			return true;
	}
}

bool MasterClass::ValidarHorarioAula(int inicio,int destino)
{
	TCurso objCurso = VecCurso[inicio-1];
	for (int i=0 ; i<VecAulas.size() ; i++)
	{
		if (destino == VecAulas[i].TAulaID )
		{
			if (VecAulas[i].horario[objCurso.dia][objCurso.horaInicio]==0 && VecAulas[i].horario[objCurso.dia][objCurso.horaInicio + 1]==0 )
			{
				return true;
			}
			else
				return false;
		}
	}
	return false;
}
bool MasterClass::ValidarHorarioProfesor(int TCursoID)
{

	TCurso objCurso = VecCurso[TCursoID-1];

	for (int i=0 ; i<VecProfesor.size() ;i++)
	{
	   if (strcmp(VecProfesor[i].nombre,objCurso.profesor.nombre)==0 && strcmp(VecProfesor[i].apellido,objCurso.profesor.apellido)==0)
	   {
		   if (VecProfesor[i].horario[objCurso.dia][objCurso.horaInicio]==0 && VecProfesor[i].horario[objCurso.dia][objCurso.horaInicio+1]==0)
		   {
			   return true;
		   }
		   else
			   return false;
	   }
	}
	return false;
}
bool MasterClass::ValidarCruceSeccion(int inicio)
{
	TCurso objCurso = VecCurso[inicio-1];
	for (int i=0 ; i<VecCursosAsignados.size() ;i++)
	{
		if(strcmp(VecCursosAsignados[i].asignatura.seccion, objCurso.asignatura.seccion)==0 && VecCursosAsignados[i].dia == objCurso.dia)
		{
			if( (VecCursosAsignados[i].horaInicio - objCurso.horaInicio)<=2 )
			{
				return false;
			} 
		}
	}
	return true;
}
bool MasterClass::ValidarSession(int inicio)
{
	 TCurso objCurso = VecCurso[inicio-1];

	 for (int i=0 ; i<VecCursosAsignados.size() ;i++)
	 {
		 if (strcmp(VecCursosAsignados[i].profesor.nombre,objCurso.profesor.nombre)==0 && strcmp(VecCursosAsignados[i].profesor.apellido,objCurso.profesor.apellido)==0 && strcmp(VecCursosAsignados[i].asignatura.seccion,objCurso.asignatura.seccion)==0 &&  VecCursosAsignados[i].sesion == objCurso.sesion)
		 {
			 return false;
		 }
	 }
	 return true;
}
void MasterClass::CambiarHorarioProfesor(int TCursoID,int dia,int hora)
{
	TCurso objCurso = VecCurso[TCursoID-1];
	for(int i=0 ; VecProfesor.size() ; i++)
	{
		if (strcmp(VecProfesor[i].nombre,objCurso.profesor.nombre)==0 && strcmp(VecProfesor[i].apellido,objCurso.profesor.apellido)==0  ) 
		{
			VecProfesor[i].horario[dia][hora] = 1;
			VecProfesor[i].horario[dia][hora+1] = 1;
		}
	}

}
void MasterClass::CambiarHorarioAula(int TAulaID,int TCursoID,int dia,int hora)
{
	  for (int i=0 ; i<VecAulas.size() ; i++)
	  {
		  if(VecAulas[i].TAulaID == TAulaID)
		  {
			VecAulas[i].horario[dia][hora]   = TCursoID;
			VecAulas[i].horario[dia][hora+1] = TCursoID;
		  }
	  }
}
void MasterClass::Cambios(int inicio, int destino)
{
 	if (inicio==0)
	{
		return;
	}
	else
	{
		int pos = VecCurso.size();
		if (inicio <= pos)
		{
			TCurso objCurso = VecCurso[inicio-1];
			CambiarHorarioProfesor(inicio,objCurso.dia,objCurso.horaInicio);			
			CambiarHorarioAula(destino,inicio,objCurso.dia,objCurso.horaInicio);
		}
		else
			return;
	}	
}
void MasterClass::insert_edge(int x, int y, int w, bool directed)
{
	g->edges[x].push_back(ii(w,y));
	g->adjMatriz[x][y] = w;
	if (!directed)
		insert_edge(y,x,w,true);
}
void MasterClass::initialize_graph() // n = num vertices
{
	this->n = VecCurso.size() + VecAulas.size() + 2;
	g->edges.resize(n);
	memset(g->adjMatriz,0,sizeof(g->adjMatriz));
}
void MasterClass::augmentPath(int v, int minEdge)
{
	if (v==s) // existe un camino
	{
		f = minEdge;
		//printf("%d\n",s);
		return;
	}
	else if (p[v]!=-1) // si existe un camino
	{
		//printf("%d<-",v);
		augmentPath(p[v],min(minEdge, g->adjMatriz[p[v]][v] ));
		g->adjMatriz[p[v]][v] -= f; // fordward
		g->adjMatriz[v][p[v]] += f; // backward
		Cambios(p[v],v);
		
	}
}
int MasterClass::edmondsKarps() //s: start, t: finish
{
	int max_flow = 0;
	while (1) // lo maximo O(VE) veces
	{
		f = 0;
		queue<int> q;
		vector<int> dist(MAX,INF);
		q.push(s);
		dist[s] = 0; // distancia origen = 0
		p.assign(MAX,-1);
		while (!q.empty())
		{
			int u = q.front();q.pop();
			if (u==t) break; // legamos al destino stop BFS
			for (int v=0;v<g->edges.size();v++)
			{
				if (g->adjMatriz[u][v] > 0 && dist[v]>=INF ) // mientras exista la arista y nodo no este ya ingresado
				{
					if(Convalidaciones(u,v))
					{
						dist[v] = dist[u]+1;
						q.push(v);
						p[v] = u;
					}
				}
			}
		}
		augmentPath(t,INF);
		if (f==0) break;
		max_flow += f;
	}
	return max_flow;
}
